package org.cheetah.core.action.spi;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessOrder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;

import org.cheetah.core.action.Action;
import org.cheetah.core.action.ActionContext;
import org.cheetah.core.action.ActionDefinition;
import org.cheetah.core.exchange.Exchange;
import org.cheetah.core.language.CompiledExpression;

@XmlRootElement(name = "if")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public class IfDefinition extends ActionDefinition {

	@XmlElement(name = "condition", required = true)
	private ExpressionDefinition expression;

	@XmlElementRef
	private List<ActionDefinition> then;

	public IfDefinition() {
		this.expression = null;
		this.then = new ArrayList<ActionDefinition>();
	}

	public IfDefinition condition(ExpressionDefinition expression) {
		this.expression = expression;
		return this;
	}

	public IfDefinition then(ActionDefinition... then) {
		this.then = Arrays.asList(then);
		return this;
	}

	public IfDefinition then(Collection<? extends ActionDefinition> then) {
		this.then = new ArrayList<ActionDefinition>(then);
		return this;
	}

	public Action createAction() throws Exception {
		return new ActionImpl(expression.compile(), new PipelineDefinition()
				.addAll(then).createAction());
	}

	private static class ActionImpl implements Action {
		private CompiledExpression condition;

		private Action then;

		ActionImpl(CompiledExpression condition, Action then) {
			this.condition = condition;
			this.then = then;
		}

		public void process(ActionContext ctx, Exchange exchange)
				throws Exception {
			if (boolean.class.cast(condition.eval(exchange, boolean.class))) {
				then.process(ActionContext.NOTHING, exchange);
			}

			ctx.process(exchange);
		}
	}
}
